package com.ice.framework.web.handler;

import com.ice.framework.common.base.ResponseResult;
import com.ice.framework.common.constant.ErrorCode;
import com.ice.framework.common.context.RequestContext;
import com.ice.framework.common.exception.BusinessException;
import com.ice.framework.common.exception.ConnectionException;
import com.ice.framework.web.helper.RequestHelper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.net.ConnectException;
import java.sql.SQLException;
import java.util.List;
import java.util.UUID;

/**
 * 异常返回类处理
 * @author wangwei
 * @Date 2021/12/22 18:11
 */
@ControllerAdvice(annotations = {RestController.class, Controller.class})
public class ResponseExceptionHandler {
    private static Logger logger = LoggerFactory.getLogger(ResponseExceptionHandler.class);


    public ResponseExceptionHandler() {
    }

    @ExceptionHandler({Exception.class})
    @ResponseBody
    public ResponseResult<Object> exceptionHandler(Exception e) {
        HttpServletRequest request = RequestHelper.getRequest();
        String errorCode;
        String errorMessage;
        if (e instanceof BusinessException) {
            errorCode = ((BusinessException) e).getCode();
            errorMessage = ((BusinessException) e).getMessage();
        } else if (this.isServerException(e)) {
            errorCode = ErrorCode.SERVER_NOT_AVAILABLE.getCode();
            errorMessage = ErrorCode.SERVER_NOT_AVAILABLE.getMessage();
        } else if (e instanceof HttpMessageNotReadableException) {
            errorCode = ErrorCode.PARAMETER_ERROR.getCode();
            errorMessage = e.getLocalizedMessage() == null ? ErrorCode.ERROR.getMessage() : e.getLocalizedMessage();
        } else if (this.isSQLException(e)) {
            errorCode = ErrorCode.SQL_EXCEPTION.getCode();
            errorMessage = this.getErroMessage(e, ErrorCode.SQL_EXCEPTION.getMessage());
        } else if (e instanceof MethodArgumentNotValidException) {
            BindingResult bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
            StringBuffer errMes = new StringBuffer();
            if (bindingResult.hasErrors()) {
                List<ObjectError> ls = bindingResult.getAllErrors();
                for (int i = 0; i < ls.size(); i++) {
                    errMes.append("[" + ls.get(i).getDefaultMessage() + "]");
                }
            } else {
                errMes.append(ErrorCode.ERROR.getMessage());
            }
            errorCode = ErrorCode.PARAM_ERROR.getCode();
            errorMessage = errMes.toString();
        } else {
            errorCode = ErrorCode.ERROR.getCode();
            errorMessage = ErrorCode.ERROR.getMessage();
        }

        String requestId = (String) request.getAttribute(RequestContext.REQUEST_ID);
        if (StringUtils.isEmpty(requestId)) {
            requestId = UUID.randomUUID().toString().replaceAll("-", "");
        }
        if (errorMessage == null) {
            errorMessage = ErrorCode.ERROR.getMessage();
        }
        if (errorMessage.length() > 2000) {
            errorMessage = errorMessage.substring(0, 2000);
        }

        ResponseResult<Object> responseResult = new ResponseResult(errorCode, errorMessage);
        responseResult.setRequestId(requestId);
        StringBuilder info = (StringBuilder) request.getAttribute(RequestContext.REQUEST_LOG_INFO);
        if (info == null) {
            info = new StringBuilder();
        }

        info.append("[==响应结果=======]>:");
        info.append("===> { errorCode:").append(errorCode).append(",errorMsg:").append(errorMessage).append("}");
        info.append("\n");
        if (e instanceof BusinessException) {
            logger.info("系统业务异常==》 \n" + info.toString(), e);
        } else {
            logger.error("系统未知异常==》 \n" + info.toString(), e);
        }

        return responseResult;
    }

    private boolean isServerException(Exception e) {
        if (!(e instanceof ConnectionException) && !(e instanceof ConnectException)) {
            if (e.getCause() == null) {
                return false;
            } else {
                Throwable cause = e.getCause();
                return cause instanceof ConnectionException || cause instanceof ConnectException;
            }
        } else {
            return true;
        }
    }

    private boolean isSQLException(Exception e) {
        if (e instanceof SQLException) {
            return true;
        } else if (e.getCause() == null) {
            return false;
        } else {
            Throwable cause = e.getCause();
            return cause instanceof SQLException;
        }
    }

    private String getErroMessage(Exception e, String errorMessage) {
        return e.getCause() != null ? e.getCause().getLocalizedMessage() : e.getLocalizedMessage();
    }
}
